using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.Protocol;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace Model.Core.Services
{
    public abstract class MqClientCtrl : IDisposable
    {
        private readonly IMqttClient _mqttClient;
        private IConfiguration _configuration;
        private readonly ILogger _logger;
        private readonly LocalRobotInfo robotInfo;
        private readonly string _willMessageTopic = "robot/device/status";
        private readonly string _onlineMessageTopic = "robot/device/online";
        private bool _disposed = false;
        private string? ServerIp { get; set; } = null;
        private int Serverport { get; set; }
        private MqttClientOptions mqttClientOptions { get; set; }
        public Action<string, string> MsgReceivedEvent { get; set; } = (topic, message) => { };

        // 新增：用于存储需要订阅的主题列表
        private readonly ConcurrentDictionary<string, byte> _topicsToSubscribe = new ConcurrentDictionary<string, byte>();
        private readonly ConcurrentDictionary<string, byte> _subscribedTopics = new ConcurrentDictionary<string, byte>();

        public bool IsConnected => _mqttClient.IsConnected;

        public MqClientCtrl(ILogger<MqClientCtrl> logger, LocalRobotInfo robotInfo)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            this.robotInfo = robotInfo ?? throw new ArgumentNullException(nameof(robotInfo));
            _mqttClient = new MqttClientFactory().CreateMqttClient();
            // 注册事件处理
            _mqttClient.ConnectedAsync += MqttClient_ConnectedAsync;
            _mqttClient.DisconnectedAsync += MqttClient_DisconnectedAsync;
            _mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;


        }

        /// <summary>
        /// 接受到消息
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            var message = Encoding.UTF8.GetString(arg.ApplicationMessage.Payload);

            _logger.LogDebug("收到消息 - Topic: {Topic}, Message: {Message}", arg.ApplicationMessage.Topic, message);

            MsgReceivedEvent?.Invoke(arg.ApplicationMessage.Topic, message);
            return Task.CompletedTask;
        }

        private async Task MqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
        {
            _logger.LogError("MQTT连接断开，原因: {arg.Reason}", arg.Reason);

            if (arg.Exception != null)
            {
                _logger.LogError(arg.Exception, "断开连接异常");
            }

            if (!_disposed)
            {
                await HandleReconnect();
            }
        }

        private async Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
        {
            _logger.LogInformation("MQTT:{ServerIp}:{Serverport} 连接成功" , ServerIp, Serverport);
            await SubscribeToTopics();
        }

        public MqttClientOptions BuildMqttClientOptions(IConfiguration mqttOptions)
        {
            _configuration = mqttOptions;
            string ClientId = mqttOptions.GetSection("ClientId")?.Value + robotInfo.RobotId + "_" + Guid.NewGuid().ToString();
            string username = mqttOptions.GetSection("UserName")?.Value ?? throw new ArgumentNullException("UserName");
            string Password = mqttOptions.GetSection("Password")?.Value ?? throw new ArgumentNullException("Password");
            TimeSpan KeepAlivePeriod = TimeSpan.FromSeconds(int.Parse(mqttOptions.GetSection("KeepAlivePeriod")?.Value ?? throw new ArgumentNullException("KeepAlivePeriod")));
            var Protocol = mqttOptions.GetSection("Protocol")?.Value ?? "tcp";
            if (!new[] { "tcp", "websocket" }.Contains(Protocol.ToLower()))
            {
                _logger.LogWarning("无效的协议类型 {Protocol}，使用默认值 tcp", Protocol);
                Protocol = "tcp";
            }
            ServerIp = mqttOptions.GetSection("Server")?.Value ?? throw new ArgumentNullException("Server");
            Serverport = int.Parse(mqttOptions.GetSection("Port")?.Value ?? throw new ArgumentNullException("Port"));
            string UriPath = mqttOptions.GetSection("WebSocketOptions:Path")?.Value ?? throw new ArgumentNullException("WebSocketOptions:Path"); ;

            var builder = new MqttClientOptionsBuilder()
               .WithClientId(ClientId)
               .WithCredentials(username, Password)
               .WithCleanSession()
               .WithKeepAlivePeriod(KeepAlivePeriod)
               .WithWillTopic(_willMessageTopic)
               .WithWillPayload(JsonSerializer.Serialize(new
               {
                   robotinfo = robotInfo,
                   status = "offline"
               }))
               .WithWillQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce);

            if (Protocol == "websocket")
            {
                builder.WithWebSocketServer(new Action<MqttClientWebSocketOptionsBuilder>(a => a.WithUri($"ws://{ServerIp}:{Serverport}{UriPath}")));
            }
            else
            {
                builder.WithTcpServer(ServerIp, Serverport);
            }

            mqttClientOptions = builder.Build();
            return mqttClientOptions;
        }

        public async Task<bool> ConnectAsync()
        {
            try
            {
                if (_mqttClient.IsConnected) return true;
                var connectResult = await _mqttClient.ConnectAsync(mqttClientOptions);
                if (connectResult == null && connectResult?.ResultCode != MqttClientConnectResultCode.Success)
                {
                    return false;
                }

                if (connectResult.ResultCode != MqttClientConnectResultCode.Success)
                {
                    throw new Exception($"连接失败: {connectResult.ResultCode}");
                }
                // 发送上线消息
                var onlineMessage = new
                {
                    robotinfo = robotInfo,
                    status = "online"
                };
                await SendMessageAsync(_onlineMessageTopic, JsonSerializer.Serialize(onlineMessage)).ConfigureAwait(false);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "MQTT连接失败");
                throw;

            }
            finally
            {

            }
        }

        public async Task DisconnectAsync()
        {
            try
            {
                await _mqttClient.DisconnectAsync();
                // 将已订阅主题移回待订阅列表
                foreach (var Item in _subscribedTopics)
                {
                    _topicsToSubscribe.TryAdd(Item.Key, 0);
                }
                _subscribedTopics.Clear();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "MQTT断开连接失败");
            }
        }

        // 将主题添加到订阅列表
        public async Task AddSubTopic(string topic)
        {
            if (!IsConnected)
            {
                _topicsToSubscribe.TryAdd(topic, 0);
                return;
            }
            if (await SubscribeAsync(topic).ConfigureAwait(false))
            {
                _subscribedTopics.TryAdd(topic, 0);
                _topicsToSubscribe.TryRemove(topic, out _);
            }
        }

        /// <summary>
        /// 批量添加订阅主题
        /// </summary>
        public async Task AddSubTopics(IEnumerable<string> topics)
        {
            if (topics == null || !topics.Any())
            {
                _logger.LogWarning("尝试添加空主题集合");
                return;
            }

            _logger.LogDebug("开始批量添加{Count}个订阅主题", topics.Count());
            
            int successCount = 0;
            foreach (var topic in topics)
            {
                try
                {
                    await AddSubTopic(topic).ConfigureAwait(false);
                    successCount++;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "添加主题订阅失败: {Topic}", topic);
                }
            }
            
            _logger.LogDebug("批量添加完成，成功{SuccessCount}/{TotalCount}个主题", 
                successCount, topics.Count());
        }

        // 订阅主题列表中的所有主题
        private async Task SubscribeToTopics()
        {
            foreach (var topic in _topicsToSubscribe.Keys.ToList())
            {
                if (await SubscribeAsync(topic).ConfigureAwait(false))
                {
                    _subscribedTopics.TryAdd(topic, 0);
                    _topicsToSubscribe.TryRemove(topic, out _);
                }
            }
        }

        private async Task<bool> SubscribeAsync(string topic)
        {
            try
            {
                await _mqttClient.SubscribeAsync(new MqttTopicFilterBuilder()
                    .WithTopic(topic)
                    .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
                    .Build());
                _logger.LogInformation("成功订阅主题: {Topic} (QoS: {QoSLevel})", topic, MqttQualityOfServiceLevel.AtMostOnce);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "订阅主题 {Topic} 失败", topic);
                return false;
            }
        }

        public async Task UnsubscribeAsync(string topic)
        {
            try
            {
                if (!_subscribedTopics.ContainsKey(topic)) return;

                await _mqttClient.UnsubscribeAsync(topic);
                _subscribedTopics.TryRemove(topic, out _);
                _logger.LogInformation("已取消订阅主题: {Topic}", topic);
            }
            catch (Exception ex)
            {
                const string unsubscribeErrorTemplate = "取消订阅主题 {Topic} 失败";
                _logger.LogError(ex, unsubscribeErrorTemplate, topic);
            }
        }

        public async Task UnsubscribeFromTopics(IEnumerable<string> topics)
        {
            foreach (var topic in topics)
            {
                await UnsubscribeAsync(topic);
            }
        }

        // 新增：清除所有订阅
        public async Task ClearAllSubscriptions()
        {
            try
            {
                var subscribedTopics = _subscribedTopics.Keys.ToList();
                if (subscribedTopics.Count > 0)
                {
                    _logger.LogInformation("开始清除所有订阅主题，数量：{Count}", subscribedTopics.Count);
                    await UnsubscribeFromTopics(subscribedTopics);
                }
                
                // 清空两个订阅集合
                _subscribedTopics.Clear();
                _topicsToSubscribe.Clear();
                _logger.LogInformation("已清除所有订阅主题");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "清除所有订阅时发生异常");
                throw;
            }
        }

        public async Task<bool> SendMessageAsync(string topic, string message)
        {
            try
            {
                if (!_mqttClient.IsConnected)
                {
                    return false;
                }

                var mqttMessage = new MqttApplicationMessageBuilder()
                    .WithTopic(topic)
                    .WithPayload(Encoding.UTF8.GetBytes(message))
                    .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
                    .Build();

                var result = await _mqttClient.PublishAsync(mqttMessage).ConfigureAwait(false);
                return result.ReasonCode == MqttClientPublishReasonCode.Success;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "消息发布失败 Topic: {Topic}", topic);
                return false;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_disposed) return;

            if (disposing)
            {
                _mqttClient?.Dispose();
                _logger.LogInformation("MQTT客户端已释放");
            }

            _disposed = true;
        }

        private async Task HandleReconnect()
        {
            var MaxRetryCount = _configuration.GetSection("MaxRetryCount")?.Value ?? "10";
            var ReconnectDelay = _configuration.GetSection("ReconnectDelay")?.Value ?? "5000";

            if (!int.TryParse(MaxRetryCount, out var retryCount) || retryCount < 0)
            {
                retryCount = 10;
                _logger.LogWarning("Invalid MaxRetryCount configuration, using default value 10");
            }
            if (!int.TryParse(ReconnectDelay, out var delay) || delay < 1000)
            {
                delay = 5000;
                _logger.LogWarning("Invalid ReconnectDelay configuration, using default value 5000ms");
            }

            for (int i = 0; i < retryCount; i++)
            {
                try
                {
   
                    _logger.LogInformation("尝试第 {RetryCount} 次重连...", i + 1);
                    await Task.Delay(delay);
                    await _mqttClient.ReconnectAsync();
                    // 重连成功后再次订阅主题
                    await SubscribeToTopics();
                    return;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "第 {i + 1} 次重连失败", i + 1);
                }
            }

            _logger.LogError("达到最大重连次数，停止重连");
        }
    }
}
